<!--
 * @description 瀑布流组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<view
		class="pure-waterfall"
		:class="_classes"
		:style="_styles"
	>
		<slot></slot>
	</view>
</template>

<script>
	import commonComponentOptions from "../../config/options";
	export default {
		options: commonComponentOptions
	};
</script>

<script setup>
	import { ref, computed, provide } from "vue";
	import props from "./props";
	import { delay } from "@/uni_modules/pure-utils";

	// -------------------------------------------------------------------------------- Refs
	// 待更新队列
	let _queue = [];
	// 所有子元素的布局信息
	const _rects = ref({});
	// 所有子元素的节点信息
	const _doms = ref({});
	// 是否正在布局中
	const _isLayouting = ref(false);
	// 容器高度
	const _height = ref(0);

	// -------------------------------------------------------------------------------- Props
	const _props = defineProps(props);

	// -------------------------------------------------------------------------------- Emits
	const _emits = defineEmits([]);

	// -------------------------------------------------------------------------------- Classes
	const _classes = computed(() => {
		const array = [];
		return array;
	});

	// -------------------------------------------------------------------------------- Styles
	const _styles = computed(() => {
		const array = [];

		// 列数
		array.push(`--pure-waterfall-cols: ${_props.cols};`);

		// 间隔
		array.push(`--pure-waterfall-gap: ${_props.gap};`);

		// 高度
		array.push(`height: calc(${_height.value}px - var(--pure-waterfall-gap) / 2);`);

		return array;
	});

	// 添加子元素节点信息
	function _addDom(dom) {
		// 存储节点信息
		_doms.value[dom.uuid] = dom;

		// 添加到待更新队列中
		_queue.push(dom);

		// 未在布局中，更新布局
		if (!_isLayouting.value) _updateLayout();
	}

	// 删除子元素节点信息
	function _deleteDom(uuid) {
		// 删除节点信息
		delete _doms.value[uuid];

		// 添加到待更新队列中
		_queue.push(uuid);

		// 未在布局中，更新布局
		if (!_isLayouting.value) _updateLayout();
	}

	// 更新布局
	async function _updateLayout() {
		// 更新布局状态
		_isLayouting.value = true;

		// 清空布局队列
		_queue = [];

		// 重新计算所有子元素的布局信息
		let rects = {};

		// 将 _doms 按 key 从小到大排序
		let doms = Object.values(_doms.value).sort((a, b) => {
			return a.index - b.index;
		});

		// 列高度
		const heights = Array(_props.cols).fill(0);

		// 遍历所有子元素
		doms.forEach((dom) => {
			// 最小列的下标
			let minColIndex = heights.indexOf(Math.min(...heights));

			// 最小列的高度
			let minColHeight = heights[minColIndex];

			// 当前子元素的高度
			let height = dom?.height || 0;

			// 计算子元素布局信息
			const rect = {
				colIndex: minColIndex, // 所属列
				top: minColHeight, // 距离顶部的距离
				isInited: true // 是否已初始化
			};
			rects[dom.uuid] = rect;

			// 更新最小列的高度
			heights[minColIndex] = minColHeight + height;

			// 更新容器高度
			_height.value = Math.max(...heights);
		});

		// 更新布局信息
		_rects.value = rects;

		// 继续计算
		// 等待一下，节省一点性能
		await delay(100);

		// 更新布局状态
		_isLayouting.value = false;

		// 如果队列不为空，则继续计算
		if (_queue.length > 0) _updateLayout();
	}

	// -------------------------------------------------------------------------------- Provides
	provide("AddPureWaterfallChildrenDOM", _addDom);
	provide("DeletePureWaterfallChildrenDOM", _deleteDom);
	provide("PureWaterfallChildrenRects", _rects);
	provide(
		"PureWaterfallCols",
		computed(() => _props.cols)
	);
	provide(
		"PureWaterfallGap",
		computed(() => _props.gap)
	);
</script>

<style scoped lang="scss">
	@import "./style.scss";
</style>
